#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);
    if(!uiInit())
    {
        qDebug("calculator init error!");
        return;
    }

    connect(num1, SIGNAL(clicked()), this, SLOT(getNum1()));
    connect(num2, SIGNAL(clicked()), this, SLOT(getNum2()));
    connect(num3, SIGNAL(clicked()), this, SLOT(getNum3()));
    connect(num4, SIGNAL(clicked()), this, SLOT(getNum4()));
    connect(num5, SIGNAL(clicked()), this, SLOT(getNum5()));
    connect(num6, SIGNAL(clicked()), this, SLOT(getNum6()));
    connect(num7, SIGNAL(clicked()), this, SLOT(getNum7()));
    connect(num8, SIGNAL(clicked()), this, SLOT(getNum8()));
    connect(num9, SIGNAL(clicked()), this, SLOT(getNum9()));
    connect(num0, SIGNAL(clicked()), this, SLOT(getNum0()));
    connect(_add, SIGNAL(clicked()), this, SLOT(getAdd()));
    connect(_sub, SIGNAL(clicked()), this, SLOT(getSub()));
    connect(_mul, SIGNAL(clicked()), this, SLOT(getMul()));
    connect(_div, SIGNAL(clicked()), this, SLOT(getDiv()));
    connect(_leftbracket, SIGNAL(clicked()), this, SLOT(getLBracket()));
    connect(_rightbracket, SIGNAL(clicked()), this, SLOT(getRBracket()));
    connect(_dot, SIGNAL(clicked()), this, SLOT(getDot()));
    connect(_clean, SIGNAL(clicked()), this, SLOT(getClean()));
    connect(_back, SIGNAL(clicked()), this, SLOT(getBackOption()));
    connect(_equal, SIGNAL(clicked()), this, SLOT(calculate()));
}

Widget::~Widget()
{
    delete ui;
}

bool Widget::uiInit()
{
    this->resize(265, 330);
    this->setWindowTitle("Calculator(retain 6 digits)");

    num7 = new QPushButton("7", this);
    num7->setFixedSize(60,40);
    num7->move(5, 125);
    num8 = new QPushButton("8", this);
    num8->setFixedSize(60,40);
    num8->move(70, 125);
    num9 = new QPushButton("9", this);
    num9->setFixedSize(60,40);
    num9->move(135, 125);
    num4 = new QPushButton("4", this);
    num4->setFixedSize(60,40);
    num4->move(5, 170);
    num5 = new QPushButton("5", this);
    num5->setFixedSize(60,40);
    num5->move(70, 170);
    num6 = new QPushButton("6", this);
    num6->setFixedSize(60,40);
    num6->move(135, 170);
    num1 = new QPushButton("1", this);
    num1->setFixedSize(60,40);
    num1->move(5, 215);
    num2 = new QPushButton("2", this);
    num2->setFixedSize(60,40);
    num2->move(70, 215);
    num3 = new QPushButton("3", this);
    num3->setFixedSize(60,40);
    num3->move(135, 215);
    num0 = new QPushButton("0", this);
    num0->setFixedSize(60,40);
    num0->move(70, 260);

    _dot = new QPushButton(".", this);
    _dot->setFixedSize(60,40);
    _dot->move(135, 260);
    _back = new QPushButton("�˸�", this);
    _back->setFixedSize(60,40);
    _back->move(5, 260);
    _equal = new QPushButton("=", this);
    _equal->setFixedSize(60,40);
    _equal->move(200, 260);
    _leftbracket = new QPushButton("(", this);
    _leftbracket->setFixedSize(60,40);
    _leftbracket->move(70, 80);
    _clean = new QPushButton("AC", this);
    _clean->setFixedSize(60,40);
    _clean->move(5, 80);
    _rightbracket = new QPushButton(")", this);
    _rightbracket->setFixedSize(60,40);
    _rightbracket->move(135, 80);

    _add= new QPushButton("+", this);
    _add->setFixedSize(60,40);
    _add->move(200, 215);
    _sub = new QPushButton("-", this);
    _sub->setFixedSize(60,40);
    _sub->move(200, 170);
    _mul = new QPushButton("*", this);
    _mul->setFixedSize(60,40);
    _mul->move(200, 125);
    _div = new QPushButton("/", this);
    _div->setFixedSize(60,40);
    _div->move(200, 80);

    _output = new QLabel("0", this);
    _output->setFixedSize(255, 60);
    _output->move(5, 5);
    _output->setAlignment(Qt::AlignRight | Qt::AlignBottom);
    _output->setStyleSheet("QLabel { background-color : white}");

    return true;
}

bool Widget::updateText(QString _text)
{
    _output->setText(_text);
    return true;
}

void Widget::getNum1()
{
    _text_ += "1";
    updateText(_text_);
}

void Widget::getNum2()
{
    _text_ += "2";
    updateText(_text_);
}

void Widget::getNum3()
{
    _text_ += "3";
    updateText(_text_);
}

void Widget::getNum4()
{
    _text_ += "4";
    updateText(_text_);
}

void Widget::getNum5()
{
    _text_ += "5";
    updateText(_text_);
}

void Widget::getNum6()
{
    _text_ += "6";
    updateText(_text_);
}

void Widget::getNum7()
{
    _text_ += "7";
    updateText(_text_);
}

void Widget::getNum8()
{
    _text_ += "8";
    updateText(_text_);
}

void Widget::getNum9()
{
    _text_ += "9";
    updateText(_text_);
}

void Widget::getNum0()
{
    _text_ += "0";
    updateText(_text_);
}

void Widget::getAdd()
{
    _text_ += "+";
    updateText(_text_);
}

void Widget::getSub()
{
    _text_ += "-";
    updateText(_text_);
}

void Widget::getMul()
{
    _text_ += "*";
    updateText(_text_);
}

void Widget::getDiv()
{
    _text_ += "/";
    updateText(_text_);
}

void Widget::getLBracket()
{
    _text_ += "(";
    updateText(_text_);
}

void Widget::getRBracket()
{
    _text_ += ")";
    updateText(_text_);
}

void Widget::getDot()
{
    if(_text_[_text_.size()-1] >= 0x30 && _text_[_text_.size()-1] <= 0x39)
    {
        _text_ += ".";
        updateText(_text_);
    }
}

void Widget::getBackOption()
{
    if(_text_.size() == 1)
    {
        _text_ = "";
        updateText(_zero);
    }
    else
    {
        _text_ = _text_.left(_text_.size() - 1);
        updateText(_text_);
    }
}

void Widget::getClean()
{
    updateText(_zero);
    _text_ = "";
    qDebug("clean text!");
}

bool Widget::wordAnalysis(vector<pair<string, int>>& word, QString _text)
{
    string expr = _text.toStdString();
    for(unsigned int i=0; i<expr.length(); ++i)
    {
        // 如果是 + - * / ( )
        if(expr[i] == '(' || expr[i] == ')' || expr[i] == '+'
            || expr[i] == '-' || expr[i] == '*' || expr[i] == '/')
        {
            string tmp;
            tmp.push_back(expr[i]);
            switch (expr[i])
            {
                case '+':
                    word.push_back(make_pair(tmp, 1));
                    break;
                case '-':
                    word.push_back(make_pair(tmp, 2));
                    break;
                case '*':
                    word.push_back(make_pair(tmp, 3));
                    break;
                case '/':
                    word.push_back(make_pair(tmp, 4));
                    break;
                case '(':
                    word.push_back(make_pair(tmp, 6));
                    break;
                case ')':
                    word.push_back(make_pair(tmp, 7));
                    break;
            }
        }
        // 如果是数字开头
        else if(expr[i]>='0' && expr[i]<='9')
        {
            string tmp;
            while(expr[i]>='0' && expr[i]<='9')
            {
                tmp.push_back(expr[i]);
                ++i;
            }
            if(expr[i] == '.')
            {
                ++i;
                if(expr[i]>='0' && expr[i]<='9')
                {
                    tmp.push_back('.');
                    while(expr[i]>='0' && expr[i]<='9')
                    {
                        tmp.push_back(expr[i]);
                        ++i;
                    }
                }
                else
                {
                    return false;  // .后面不是数字，词法错误
                }
            }
            word.push_back(make_pair(tmp, 5));
            --i;
        }
        // 如果以.开头
        else
        {
            return false;  // 以.开头，词法错误
        }
    }
    return true;
}

void Widget::Next()
{
    if(idx < word.size())
        sym = word[idx++].second;
    else
        sym = 0;
}

// E → TE'
void Widget::E()
{
    T();
    E1();
}

// E' → +TE' | -TE' | ε
void Widget::E1()
{
    if(sym == 1)
    {
        Next();
        T();
        E1();
    }
    else if(sym == 2)
    {
        Next();
        T();
        E1();
    }
    else if(sym != 7 && sym != 0)
    {
        err = -1;
    }
}

// T → FT' 
void Widget::T()
{
    F();
    T1();
}

// T' → *FT' | /FT' | ε 
void Widget::T1()
{
    if(sym == 3)
    {
        Next();
        F();
        T1();
    }
    else if(sym == 4)
    {
        Next();
        F();
        T1();
    }
    else if(sym != 1 && sym != 2 && sym != 7 && sym != 0)
    {
        err = -1;
    }
}

// F → (E) | d
void Widget::F()
{
    if(sym == 5)
    {
        Next();
    }
    else if(sym == 6)
    {
        Next();
        E();
        if(sym == 7)
        {
            Next();
        }
        else
        {
            err = -1;
        }
    }
    else
    {
        err = -1;
    }
}

int Widget::prior(int token)
{
    switch(token)
    {
    case 1:
    case 2:
        return 1;
    case 3:
    case 4:
        return 2;
    default:
        return 0;
    }
}

bool Widget::isOperator(int token)
{
    switch(token)
    {
    case 1:
    case 2:
    case 3:
    case 4:
        return true;
    default:
        return false;
    }
}

vector<pair<string, int>> Widget::getPostfix(vector<pair<string, int>> expr)
{
    vector<pair<string, int>> output;
    stack<pair<string, int>> op;
    for(unsigned int i = 0; i < expr.size(); i++)
    {
        pair<string, int> p = expr[i];
        if(isOperator(p.second))
        {
            while(!op.empty() && isOperator(op.top().second) && prior(op.top().second) >= prior(p.second))
            {
                output.push_back(op.top());
                op.pop();
            }
            op.push(p);
        }
        else if (p.second == 6)
        {
            op.push(p);
        }
        else if (p.second == 7)
        {
            while(op.top().second != 6)
            {
                output.push_back(op.top());
                op.pop();
            }
            op.pop();
        }
        else
        {
            output.push_back(p);
        }
    }
    while(!op.empty())
    {
        output.push_back(op.top());
        op.pop();
    }
    return output;
}

void Widget::popTwoNum(stack<double> &numStack, double &first, double &second)
{
    first = numStack.top();
    numStack.pop();
    second = numStack.top();
    numStack.pop();
}

double strToDouble(const string &str)
{
    double ans;
    stringstream ss;
    ss << str;
    ss >> ans;
    return ans;
}

double Widget::getAnswer(const vector<pair<string, int>> &postfix)
{
    double first, second;
    stack<double> num;
    for(unsigned int i = 0; i < postfix.size(); i++)
    {
        pair<string, int> p = postfix[i];
        switch(p.second)
        {
        case 1:
            popTwoNum(num, first, second);
            num.push(second + first);
            break;
        case 2:
            popTwoNum(num, first, second);
            num.push(second - first);
            break;
        case 3:
            popTwoNum(num, first, second);
            num.push(second * first);
            break;
        case 4:
            popTwoNum(num, first, second);
            num.push(second / first);
            break;
        default:
            num.push(strToDouble(p.first));
            break;
        }
    }
    double result = num.top();
    num.pop();
//    qDebug() << "the result is: " << num.top() << endl;
    return result;
}

void Widget::calculate()
{
    word.clear(); idx = 0; err = 0;
    if(_text_[0] == '-')
        _text_ = "0" + _text_;
    else
        _text_ = "0+" + _text_;
    int err_num = wordAnalysis(word, _text_);
    cout << _text_.toStdString() << endl << "Word Analysis:" << endl;
    if (-1 == err_num)
    {
        cout << "Word Error!" << endl;
    }
    else
    {
        // 测试输出
        vector<pair<string, int>>::iterator beg = word.begin();
        for(;beg!=word.end(); ++beg)
            cout << "   (" << beg->first << ", " << beg->second << ")" << endl;

        // 词法正确，进行语法分析
        Next();
        E();
        if (sym || err)  // 注意要判断两个条件
            cout << "Wrong Expression." << endl;
        else
        {
            cout << "Correct Expression." << endl;
            vector<pair<string, int>> postfix = getPostfix(word);
            beg = postfix.begin();
            for(;beg!=postfix.end(); ++beg)
                cout << "   (" << beg->first << ", " << beg->second << ")" << endl;
            double answer = getAnswer(postfix);
            qDebug() << "the answer is: " << answer << endl;
            string double_to_str = std::to_string(answer);
            _text_ = QString::fromStdString(double_to_str);
            while(_text_[_text_.size()-1] == '0')
                _text_ = _text_.left(_text_.size() - 1);
            if(_text_[_text_.size()-1] == '.')
                _text_ = _text_.left(_text_.size() - 1);
            updateText(_text_);
            return;
        }
    }

}
